package com.group4.datafactorybackend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.group4.datafactorybackend.common.R;
import com.group4.datafactorybackend.common.enums.MyEnumClass;
import com.group4.datafactorybackend.common.enums.ResultCodeEnum;
import com.group4.datafactorybackend.entity.DO.DataSourceMessageDO;
import com.group4.datafactorybackend.entity.DO.DatabaseTypeDO;
import com.group4.datafactorybackend.entity.DTO.CreateOrUpdateDataSourceMessageDTO;
import com.group4.datafactorybackend.entity.DTO.BatchReleaseOrOutageDTO;
import com.group4.datafactorybackend.entity.DTO.ConnectTestDTO;
import com.group4.datafactorybackend.entity.DTO.SelectDataSourceMessageDTO;
import com.group4.datafactorybackend.entity.VO.DatabaseTypeVO;
import com.group4.datafactorybackend.entity.VO.SelectDataSourceMessageVO;
import com.group4.datafactorybackend.mapper.DataSourceMapper;
import com.group4.datafactorybackend.mapper.DatabaseTypeMapper;
import com.group4.datafactorybackend.service.DataSourceService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author aKUN
 * @date 2022/7/28
 * @description 数据源管理业务逻辑实现层
 */
@Service
public class DataSourceServiceImpl extends ServiceImpl<DataSourceMapper, DataSourceMessageDO> implements DataSourceService {

    @Autowired
    private DataSourceMapper dataSourceMapper;

    @Autowired
    private DatabaseTypeMapper databaseTypeMapper;

    /**
     * @author aKUN
     * @param selectDataSourceMessageDTO 用于查询和分页展示
     * @return R
     * @description 数据库管理分页
     **/
    @Override
    public R<?> selectDateSourceByPage(SelectDataSourceMessageDTO selectDataSourceMessageDTO) {
        IPage<DataSourceMessageDO> dataSourceMessagePage = new Page<>(selectDataSourceMessageDTO.getPageNum(), selectDataSourceMessageDTO.getPageSize());
        LambdaQueryWrapper<DataSourceMessageDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        //根据数据源名称查询
        lambdaQueryWrapper.like(StringUtils.isNotBlank(selectDataSourceMessageDTO.getDsmName()), DataSourceMessageDO::getDsmName, selectDataSourceMessageDTO.getDsmName())
                //根据数据状态查询
                .eq(StringUtils.isNotBlank(selectDataSourceMessageDTO.getDsmStatus()), DataSourceMessageDO::getDsmStatus, selectDataSourceMessageDTO.getDsmStatus())
                //状态进行顺序排列
                .orderByAsc(DataSourceMessageDO::getDsmStatus)
                //时间倒叙排序
                .orderByDesc(DataSourceMessageDO::getUpdateTime)
                ;

        dataSourceMessagePage = dataSourceMapper.selectPage(dataSourceMessagePage, lambdaQueryWrapper);

        LambdaQueryWrapper<DatabaseTypeDO> databaseTypeLambdaQueryWrapper = new LambdaQueryWrapper<>();
        List<SelectDataSourceMessageVO> selectDataSourceMessageList = new ArrayList<>();
        for (DataSourceMessageDO dataSourceMessage : dataSourceMessagePage.getRecords()) {
            // 将分页中返回的集合中的DO对象赋值为VO对象
            SelectDataSourceMessageVO selectDataSourceMessage = new SelectDataSourceMessageVO();
            BeanUtils.copyProperties(dataSourceMessage, selectDataSourceMessage);
            databaseTypeLambdaQueryWrapper.clear();
            databaseTypeLambdaQueryWrapper.eq(DatabaseTypeDO::getDtCode, dataSourceMessage.getDtCode());
            DatabaseTypeDO databaseTypeDO = databaseTypeMapper.selectOne(databaseTypeLambdaQueryWrapper);
            // 向展示的VO对象中添加dtName属性值
            selectDataSourceMessage.setDtName(databaseTypeDO.getDtName());
            // 将VO对象添加进集合中
            selectDataSourceMessageList.add(selectDataSourceMessage);
        }
        IPage<SelectDataSourceMessageVO> selectDataSourceMessagePage = new Page<>();
        selectDataSourceMessagePage.setTotal(dataSourceMessagePage.getTotal());
        selectDataSourceMessagePage.setRecords(selectDataSourceMessageList);
        return R.Success(selectDataSourceMessagePage);
    }

    /**
     * @author 牟屿洋
     * @param createOrUpdateDataSourceMessageDTO 新增、编辑数据源信息接收参数实体类
     * @return R
     * @description 编辑数据源信息
     */
    @Override
    public R<?> updateDataSource(CreateOrUpdateDataSourceMessageDTO createOrUpdateDataSourceMessageDTO) {
        // 查重
        LambdaQueryWrapper<DataSourceMessageDO> isRepeatWrapper = new LambdaQueryWrapper<>();
        isRepeatWrapper.eq(DataSourceMessageDO::getDsmName, createOrUpdateDataSourceMessageDTO.getDsmName())
                .ne(DataSourceMessageDO::getId, createOrUpdateDataSourceMessageDTO.getId());
        int nameCount = dataSourceMapper.selectCount(isRepeatWrapper);
        if (nameCount > 0) {
            return R.Failed(ResultCodeEnum.DATA_SOURCE_NAME_REPEAT);
        }
        // 清除匹配信息
        isRepeatWrapper.clear();
        isRepeatWrapper.eq(DataSourceMessageDO::getDsmConnectInfo, createOrUpdateDataSourceMessageDTO.getDsmConnectInfo())
                .ne(DataSourceMessageDO::getId, createOrUpdateDataSourceMessageDTO.getId());
        int infoCount = dataSourceMapper.selectCount(isRepeatWrapper);
        if (infoCount > 0) {
            return R.Failed(ResultCodeEnum.DATA_SOURCE_JDBC_URL_REPEAT);
        }

        LambdaQueryWrapper<DataSourceMessageDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DataSourceMessageDO::getId, createOrUpdateDataSourceMessageDTO.getId());

        DataSourceMessageDO dataSourceMessageDO = new DataSourceMessageDO();
        BeanUtils.copyProperties(createOrUpdateDataSourceMessageDTO, dataSourceMessageDO);

        int result = dataSourceMapper.update(dataSourceMessageDO, queryWrapper);
        if(result <= 0 ){
            return R.Failed(ResultCodeEnum.OPERATION_FAILED);
        }
        return R.Success(ResultCodeEnum.OPERATION_SUCCESS);
    }

    /**
     * @author 牟屿洋
     * @param batchReleaseOrOutageDTO （批量）发布/停用接收参数实体类
     * @return R
     * @description （批量）发布/停用数据源信息
     */
    @Override
    public R<?> releaseOrOutage(BatchReleaseOrOutageDTO batchReleaseOrOutageDTO) {
        Integer status = batchReleaseOrOutageDTO.getStatus();
        List<String> dataSourceCodeList = batchReleaseOrOutageDTO.getCodeList();

        // 判断批量停用时，是否含有未发布的数据源信息
        if (status.equals(MyEnumClass.StatusEnum.HAVE_DISABLE.getCode())) {
            LambdaQueryWrapper<DataSourceMessageDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(DataSourceMessageDO::getDsmStatus, MyEnumClass.StatusEnum.NOT_RELEASE.getCode())
                    .in(DataSourceMessageDO::getId, dataSourceCodeList);
            int result = dataSourceMapper.selectCount(lambdaQueryWrapper);
            if (result > 0) {
                return R.Failed(ResultCodeEnum.EXIST_NOT_RELEASE.getCode(), "存在未发布的数据源");
            }
        }
        // 判断批量发布时，是否含有已发布的数据源信息
        if (status.equals(MyEnumClass.StatusEnum.HAVE_RELEASE.getCode())) {
            LambdaQueryWrapper<DataSourceMessageDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(DataSourceMessageDO::getDsmStatus, MyEnumClass.StatusEnum.HAVE_RELEASE.getCode())
                    .in(DataSourceMessageDO::getId, dataSourceCodeList);
            int result = dataSourceMapper.selectCount(lambdaQueryWrapper);
            if (result > 0) {
                return R.Failed(ResultCodeEnum.EXIST_HAVE_RELEASE.getCode(), "存在已发布的数据源");
            }
        }

        // （批量）发布/停用
        LambdaUpdateWrapper<DataSourceMessageDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(DataSourceMessageDO::getId, dataSourceCodeList)
                .set(DataSourceMessageDO::getDsmStatus, status);
        int result = dataSourceMapper.update(null, updateWrapper);
        if(result <= 0) {
            return R.Failed(ResultCodeEnum.OPERATION_FAILED);
        }
        return R.Success(ResultCodeEnum.OPERATION_SUCCESS);
    }

    /**
     * @author OKer
     * @return R
     * @description 查询所有数据库类型
     **/
    @Override
    public R<?> findAllDatabaseType() {
        LambdaQueryWrapper<DatabaseTypeDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        List<DatabaseTypeDO> databaseTypeDOList = databaseTypeMapper.selectList(lambdaQueryWrapper);
        List<DatabaseTypeVO> databaseTypeVOList = databaseTypeDOList.stream().map(e->{
            DatabaseTypeVO databaseTypeVO = new DatabaseTypeVO();
            databaseTypeVO.setDtCode(e.getDtCode());
            databaseTypeVO.setDtName(e.getDtName());
            return databaseTypeVO;
        }).collect(Collectors.toList());
        return R.Success(databaseTypeVOList);
    }

    /**
    * @author OKer
    * @param createOrUpdateDataSourceMessageDTO 新增、编辑数据源信息接收参数实体类
    * @return R
    * @description 新增数据源连接信息
    **/
    @Override
    public R<?> addDataSource(CreateOrUpdateDataSourceMessageDTO createOrUpdateDataSourceMessageDTO) {
        // 查询数据库中是否已存在数据源名称或数据源连接信息
        LambdaQueryWrapper<DataSourceMessageDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DataSourceMessageDO::getDsmName, createOrUpdateDataSourceMessageDTO.getDsmName());
        int nameExistNum = dataSourceMapper.selectCount(lambdaQueryWrapper);
        if (nameExistNum > 0) {
            return R.Failed(ResultCodeEnum.DATA_SOURCE_NAME_REPEAT);
        }
        lambdaQueryWrapper.clear();
        lambdaQueryWrapper.eq(DataSourceMessageDO::getDsmConnectInfo,createOrUpdateDataSourceMessageDTO.getDsmConnectInfo());
        int infoExistNum = dataSourceMapper.selectCount(lambdaQueryWrapper);
        if (infoExistNum > 0){
            return R.Failed(ResultCodeEnum.DATA_SOURCE_JDBC_URL_REPEAT);
        }

        DataSourceMessageDO dataSourceMessageDO = new DataSourceMessageDO();
        BeanUtils.copyProperties(createOrUpdateDataSourceMessageDTO,dataSourceMessageDO);
        int result = dataSourceMapper.insert(dataSourceMessageDO);
        if (result <= 0){
            R.Failed(ResultCodeEnum.OPERATION_FAILED);
        }
        return R.Success(ResultCodeEnum.OPERATION_SUCCESS);
    }

    /**
     * @author dwl
     * @param id 主键ID
     * @return R
     * @description 删除数据源
     */
    @Override
    public R<?> deleteSource(Long id) {
        LambdaQueryWrapper<DataSourceMessageDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DataSourceMessageDO::getId,id);
        int delete = dataSourceMapper.delete(queryWrapper);
        if (delete>0){
            return R.Success(ResultCodeEnum.OPERATION_SUCCESS);
        }
        return R.Failed(ResultCodeEnum.OPERATION_FAILED);
    }

    /**
     * @author 卑微小峰
     * @param connectTestDTO 数据源连通测试接收参数实体类
     * @return R
     * @description 连接测试数据源
     */
    @Override
    public R<?> connectTest(ConnectTestDTO connectTestDTO) {
        try {
            Class.forName(connectTestDTO.getDsmDriverName());
            Connection connection = DriverManager.getConnection(connectTestDTO.getDsmConnectInfo(), connectTestDTO.getDsmUsername(), connectTestDTO.getDsmPassword());
            connection.close();
            if (ObjectUtils.isEmpty(connection)) {
                return R.Failed(ResultCodeEnum.CONNECT_TEST_FAILED, ResultCodeEnum.CONNECT_TEST_FAILED.getMessage());
            }
            return R.Success(ResultCodeEnum.CONNECT_TEST_SUCCESS, ResultCodeEnum.CONNECT_TEST_SUCCESS.getMessage());
        } catch (Exception e) {
            return R.Failed(ResultCodeEnum.CONNECT_TEST_FAILED, ResultCodeEnum.CONNECT_TEST_FAILED.getMessage());
        }
    }
}
